﻿using System;
using FluentParser.Expressions;
using FluentParser.Expressions.Terminals.Parsing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FluentParser.Tests.Expressions.Terminals.Parsing
{
    [TestClass]
    public class ParseRegexExpressionTerminalTests
    {
        [TestMethod]
        public void Parse_WhenParsingValidText_ShouldReturnTheText()
        {
            ParseRegexExpressionTerminal<string> expr = new ParseRegexExpressionTerminal<string>("ValidText", x => x.Value);
            ParsingResult<string> result = expr.Parse("ValidTextFollowedBySomethingElse");
            string expected = "ValidText";
            string actual = result.Value;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(expected.Length, result.Length);
        }

        [TestMethod]
        public void Parse_WhenParsingInvalidText_ShouldReturnNull()
        {
            ParseRegexExpressionTerminal<string> expr = new ParseRegexExpressionTerminal<string>("InvalidText", x => x.Value);

            var expected = (ParsingResult<string>)null;
            var actual = expr.Parse("SomethingElse");

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void Parse_WhenParsingASentenceUsingAlphaRegex_ShouldReturnTheFirstWord()
        {
            ParseRegexExpressionTerminal<string> expr = new ParseRegexExpressionTerminal<string>("[A-Za-z]+", x => x.Value);
            ParsingResult<string> result = expr.Parse("This is a sentence.");

            string expected = "This";
            string actual = result.Value;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(expected.Length, result.Length);
        }

        [TestMethod]
        public void Parse_WhenParsingANumberWithIntegerConversion_ShouldReturnAnInteger()
        {
            ParseRegexExpressionTerminal<int> expr = new ParseRegexExpressionTerminal<int>("[0-9]+", x => Int32.Parse(x.Value));
            ParsingResult<int> result = expr.Parse("1234SomethingElse");

            int expected = 1234;
            int actual = result.Value;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(4, result.Length);
        }

        [TestMethod]
        public void ParseNode_WhenParsingValidText_ShouldReturnTheText()
        {
            ParseRegexExpressionTerminal<string> expr = new ParseRegexExpressionTerminal<string>("ValidText", x => x.Value);
            ParsingNodeResult node = expr.ParseNode("ValidTextFollowedBySomethingElse");

            string expected = "ValidText";
            string actual = node.Value as string;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(expected.Length, node.Length);
        }

        [TestMethod]
        public void ParseNode_WhenParsingInvalidText_ShouldReturnNull()
        {
            ParseRegexExpressionTerminal<string> expr = new ParseRegexExpressionTerminal<string>("InvalidText", x => x.Value);
            ParsingNodeResult node = expr.ParseNode("SomethingElse");

            string expected = null;
            string actual = node.Value as string;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(0, node.Length);
            Assert.AreEqual(1, node.ExploredLength);
        }

        [TestMethod]
        public void ParseNode_WhenParsingASentenceUsingAlphaRegex_ShouldReturnTheFirstWord()
        {
            ParseRegexExpressionTerminal<string> expr = new ParseRegexExpressionTerminal<string>("[A-Za-z]+", x => x.Value);
            ParsingNodeResult node = expr.ParseNode("This is a sentence.");

            string expected = "This";
            string actual = node.Value as string;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(expected.Length, node.Length);
        }

        [TestMethod]
        public void ParseNode_WhenParsingANumberWithIntegerConversion_ShouldReturnAnInteger()
        {
            ParseRegexExpressionTerminal<int> expr = new ParseRegexExpressionTerminal<int>("[0-9]+", x => Int32.Parse(x.Value));
            ParsingNodeResult node = expr.ParseNode("1234SomethingElse");

            int expected = 1234;
            int actual = (int)node.Value;

            Assert.AreEqual(expected, actual);
            Assert.AreEqual(4, node.Length);

            // BUG: ExploredLength is wrong because Regex doesn't provide this information
            //Assert.AreEqual(5, node.ExploredLength); 
        }
    }
}
